home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 276_01 / az80eval.c < prev    next >
C/C++ Source or Header  |  1989-10-01  |  12KB  |  485 lines

  1. /*
  2.     HEADER:        CUG276;
  3.     TITLE:        Z-80 Cross-Assembler (Portable);
  4.     FILENAME:    AZ80EVAL.C;
  5.     VERSION:    0.1;
  6.     DATE:        08/27/1988;
  7.     SEE-ALSO:    AZ80.H;
  8.     AUTHORS:    William C. Colley III;
  9. */
  10.  
  11. /*
  12.               Z-80 Cross-Assembler in Portable C
  13.  
  14.         Copyright (c) 1986-1988 William C. Colley, III
  15.  
  16. Revision History:
  17.  
  18. Ver    Date        Description
  19.  
  20. 0.0    JUNE 1988    Derived from my S6 cross-assembler.  WCC3.
  21.  
  22. 0.1    AUG 1988    Fixed a bug in the command line parser that puts it
  23.             into a VERY long loop if the user types a command line
  24.             like "AZ80 FILE.ASM -L".  WCC3 per Alex Cameron.
  25.  
  26. This file contains the assembler's expression evaluator and lexical analyzer.
  27. The lexical analyzer chops the input character stream up into discrete tokens
  28. that are processed by the expression analyzer and the line assembler.  The
  29. expression analyzer processes the token stream into unsigned results of
  30. arithmetic expressions.
  31. */
  32.  
  33. /*  Get global goodies:  */
  34.  
  35. #include "az80.h"
  36.  
  37. /*  Get access to global mailboxes defined in AZ80.C:            */
  38.  
  39. extern char line[];
  40. extern int filesp, forwd, pass;
  41. extern unsigned pc;
  42. extern FILE *filestk[], *source;
  43. extern TOKEN arg, token;
  44.  
  45. /*  Machine opcode argument field parsing routine.  The token stream    */
  46. /*  from the lexical analyzer is processed to extract addresses and    */
  47. /*  addressing mode information.  The resulting value is passed back    */
  48. /*  through the same type of token buffer that the lexical analyzer    */
  49. /*  uses.  In addition, the addressing mode information is returned as    */
  50. /*  the    function return value.                        */
  51.  
  52. static int bad;
  53.  
  54. unsigned get_arg()
  55. {
  56.     SCRATCH int c;
  57.     SCRATCH unsigned a, u;
  58.     TOKEN *lex();
  59.     int popc();
  60.     unsigned eval(), expr();
  61.     void exp_error(), pushc(), trash(), unlex();
  62.  
  63.     a = NUM;  u = 0;  bad = FALSE;
  64.     switch (lex() -> attr & TYPE) {
  65.     case SEP:   exp_error('S');  a = NONE;  break;
  66.  
  67.     case EOL:   unlex();  a = NONE;  break;
  68.  
  69.     case REG:   a = token.valu;  break;
  70.  
  71.     case OPR:   if (token.valu == '(') {
  72.             if ((lex() -> attr & TYPE) == REG) {
  73.                 a = token.valu;  lex();
  74.                 switch (a) {
  75.                 case C:        a = C_IND;  break;
  76.  
  77.                 case BC:
  78.                 case DE:
  79.                 case SP:    a += SP_IND - SP;  break;
  80.  
  81.                 case HL:    a = HL_IND;  break;
  82.  
  83.                 case IX:    a = IX_IND;  goto do_ix_ind;
  84.  
  85.                 case IY:    a = IY_IND;
  86. do_ix_ind:                    if ((token.attr & TYPE) == OPR &&
  87.                         (token.valu == '+' ||
  88.                         token.valu == '-')) {
  89.                         unlex();
  90.                         if ((u = eval(LPREN)) > 0x7f
  91.                             && u < 0xff80)
  92.                             exp_error('V');
  93.                         }
  94.                         break;
  95.  
  96.                 default:    exp_error('R');  break;
  97.                 }
  98.                 if ((token.attr & TYPE) != OPR ||
  99.                 token.valu != ')') exp_error(')');
  100.                 break;
  101.             }
  102.             else {
  103.                 unlex();  u = eval(LPREN);
  104.                 trash();  pushc(c = popc());
  105.                 if (c == ',' || c == '\n') {
  106.                 a = NUM_IND;  break;
  107.                 }
  108.                 token.attr = VAL;  token.valu = u;
  109.             }
  110.             }
  111.  
  112.     case VAL:
  113.     case STR:   unlex();  u = eval(START);  unlex();  break;
  114.     }
  115.     arg.valu = bad ? 0 : u;  return arg.attr = a;
  116. }
  117.  
  118. /*  Expression analysis routine.  The token stream from the lexical    */
  119. /*  analyzer is processed as an arithmetic expression and reduced to an    */
  120. /*  unsigned value.  If an error occurs during the evaluation, the    */
  121. /*  global flag    forwd is set to indicate to the line assembler that it    */
  122. /*  should not base certain decisions on the result of the evaluation.    */
  123.  
  124. unsigned expr()
  125. {
  126.     SCRATCH unsigned u;
  127.     unsigned eval();
  128.  
  129.     bad = FALSE;
  130.     u = eval(START);
  131.     return bad ? 0 : u;
  132. }
  133.  
  134. static unsigned eval(pre)
  135. unsigned pre;
  136. {
  137.    register unsigned op, u, v;
  138.    TOKEN *lex();
  139.    void exp_error(), unlex();
  140.  
  141.    for (;;) {
  142.       u = op = lex() -> valu;
  143.       switch (token.attr & TYPE) {
  144.      case REG:   exp_error('S');  break;
  145.  
  146.      case SEP:   if (pre != START) unlex();
  147.      case EOL:   exp_error('E');  return;
  148.  
  149.      case OPR:   if (!(token.attr & UNARY)) { exp_error('E');  break; }
  150.              u = eval((op == '+' || op == '-') ?
  151.                (unsigned) UOP1 : token.attr & PREC);
  152.              switch (op) {
  153.             case '-':   u = word(-u);  break;
  154.  
  155.             case NOT:   u ^= 0xffff;  break;
  156.  
  157.             case HIGH:  u = high(u);  break;
  158.  
  159.             case LOW:   u = low(u);  break;
  160.              }
  161.  
  162.      case VAL:    
  163.      case STR:   for (;;) {
  164.             op = lex() -> valu;
  165.             switch (token.attr & TYPE) {
  166.                case REG:   exp_error('S');  break;
  167.  
  168.                case SEP:   if (pre != START) unlex();
  169.                case EOL:   if (pre == LPREN) exp_error('(');
  170.                        return u;
  171.  
  172.                case STR:
  173.                case VAL:   exp_error('E');  break;
  174.  
  175.                case OPR:   if (!(token.attr & BINARY)) {
  176.                       exp_error('E');  break;
  177.                        }
  178.                        if ((token.attr & PREC) >= pre) {
  179.                       unlex();  return u;
  180.                        }
  181.                        if (op != ')')
  182.                       v = eval(token.attr & PREC);
  183.                        switch (op) {
  184.                       case '+':   u += v;  break;
  185.  
  186.                       case '-':   u -= v;  break;
  187.  
  188.                       case '*':   u *= v;  break;
  189.  
  190.                       case '/':   u /= v;  break;
  191.  
  192.                       case MOD:   u %= v;  break;
  193.  
  194.                       case AND:   u &= v;  break;
  195.  
  196.                       case OR:    u |= v;  break;
  197.  
  198.                       case XOR:   u ^= v;  break;
  199.  
  200.                       case '<':   u = u < v;  break;
  201.  
  202.                       case LE:    u = u <= v;  break;
  203.  
  204.                       case '=':   u = u == v;  break;
  205.  
  206.                       case GE:    u = u >= v;  break;
  207.  
  208.                       case '>':   u = u > v;  break;
  209.  
  210.                       case NE:    u = u != v;  break;
  211.  
  212.                       case SHL:   if (v > 15)
  213.                              exp_error('E');
  214.                               else u <<= v;
  215.                               break;
  216.  
  217.                       case SHR:   if (v > 15)
  218.                              exp_error('E');
  219.                               else u >>= v;
  220.                               break;
  221.  
  222.                       case ')':   if (pre == LPREN)
  223.                              return u;
  224.                               exp_error('(');
  225.                               break;
  226.                        }
  227.                        clamp(u);
  228.                        break;
  229.             }
  230.              }
  231.              break;
  232.       }
  233.    }
  234. }
  235.  
  236. static void exp_error(c)
  237. char c;
  238. {
  239.     forwd = bad = TRUE;  error(c);
  240. }
  241.  
  242. /*  Lexical analyzer.  The source input character stream is chopped up    */
  243. /*  into its component parts and the pieces are evaluated.  Symbols are    */
  244. /*  looked up, operators are looked up, etc.  Everything gets reduced    */
  245. /*  to an attribute word, a numeric value, and (possibly) a string    */
  246. /*  value.                                */
  247.  
  248. static int oldt = FALSE;
  249. static int quote = FALSE;
  250.  
  251. TOKEN *lex()
  252. {
  253.     SCRATCH char c, *p;
  254.     SCRATCH unsigned b;
  255.     SCRATCH OPCODE *o;
  256.     SCRATCH SYMBOL *s;
  257.     OPCODE *find_operator();
  258.     SYMBOL *find_symbol();
  259.     void exp_error(), make_number(), pops(), pushc(), trash();
  260.  
  261.     if (oldt) { oldt = FALSE;  return &token; }
  262.     trash();
  263.     if (isalph(c = popc())) {
  264.     pushc(c);  pops(token.sval);
  265.     if (o = find_operator(token.sval)) {
  266.         token.attr = o -> attr;  token.valu = o -> valu;
  267.     }
  268.     else {
  269.         token.attr = VAL;
  270.         if (!strcmp(token.sval,"$")) token.valu = pc;
  271.         else if (s = find_symbol(token.sval)) {
  272.         token.valu = s -> valu;
  273.         if (pass == 2 && s -> attr & FORWD) forwd = TRUE;
  274.         }
  275.         else { token.valu = 0;  exp_error('U'); }
  276.     }
  277.     }
  278.     else if (isnum(c)) {
  279.     pushc(c);  pops(token.sval);
  280.     for (p = token.sval; p[1]; ++p);
  281.     switch (toupper(*p)) {
  282.         case 'B':    b = 2;  break;
  283.  
  284.         case 'O':
  285.         case 'Q':    b = 8;  break;
  286.  
  287.         default:    ++p;
  288.         case 'D':    b = 10;  break;
  289.  
  290.         case 'H':    b = 16;  break;
  291.     }
  292.     *p = '\0';  make_number(b);
  293.     }
  294.     else switch (c) {
  295.     case '(':   token.attr = UNARY + LPREN + OPR;
  296.             goto opr1;
  297.  
  298.     case ')':   token.attr = BINARY + RPREN + OPR;
  299.             goto opr1;
  300.  
  301.     case '+':   token.attr = BINARY + UNARY + ADDIT + OPR;
  302.             goto opr1;
  303.  
  304.     case '-':   token.attr = BINARY + UNARY + ADDIT + OPR;
  305.             goto opr1;
  306.  
  307.     case '*':   token.attr = BINARY + UNARY + MULT + OPR;
  308.             goto opr1;
  309.  
  310.     case '/':   token.attr = BINARY + MULT + OPR;
  311. opr1:            token.valu = c;
  312.             break;
  313.  
  314.     case '<':   token.valu = c;
  315.             if ((c = popc()) == '=') token.valu = LE;
  316.             else if (c == '>') token.valu = NE;
  317.             else pushc(c);
  318.             goto opr2;
  319.  
  320.     case '=':   token.valu = c;
  321.             if ((c = popc()) == '<') token.valu = LE;
  322.             else if (c == '>') token.valu = GE;
  323.             else pushc(c);
  324.             goto opr